package com.andnnl.future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * Created by chenss on 2019/12/30.
 */
public class CompletableFutureTest {
    static Logger logger= LoggerFactory.getLogger(CompletableFutureTest.class);
    public static void main(String[] args) throws Exception {
        System.out.println("run start ...");
//        test0();
//        runAsync();//runAsync方法不支持返回值。
//        supplyAsync();//supplyAsync可以支持返回值。

//        whenComplete();
//        whenCompleteJava8();



        testAll();
        System.out.println("run end ...");
    }

    private static void testAll() {
        List<CompletableFuture<Integer>> list=new ArrayList<>();
        for (int i = 0; i < 200; i++) {
            CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
                logger.info("sl...");
                ThreadUtil.sleep(1000);
//                throw new RuntimeException("1");
                return 20;
            });
            list.add(future);
        }
        CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
        System.out.println("all end");
    }

    private static void test0() throws InterruptedException, java.util.concurrent.ExecutionException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            ThreadUtil.sleep(100);
            return 20;
        }).whenCompleteAsync((v, e) -> {
            System.out.println(v);
            System.out.println(e);
        });
        System.out.println(future.get());
    }


    //无返回值
    public static void runAsync() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
            }
            System.out.println("runAsync end ...");
            throw new RuntimeException("eee");
        });

        System.out.println(future.get());
    }

    //有返回值
    public static void supplyAsync() throws Exception {
        CompletableFuture<Long> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            System.out.println("run end ...");
            return System.currentTimeMillis();
        });

        long time = future.get();
        System.out.println("time = "+time);
    }

    /**
     * whenComplete 和 whenCompleteAsync 的区别：
     * whenComplete：是执行当前任务的线程执行继续执行 whenComplete 的任务。
     * whenCompleteAsync：是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
     * @throws Exception
     */
    public static void whenComplete() throws Exception {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                System.out.println(Thread.currentThread().getName()+" sleep...1" );
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
            }
            if(new Random().nextInt()%2>=0) {
                int i = 12/0;
            }
            System.out.println(Thread.currentThread().getName()+" run end ...");
        });

        future.whenComplete(new BiConsumer<Void, Throwable>() {
//        future.whenCompleteAsync(new BiConsumer<Void, Throwable>() {
            @Override
            public void accept(Void t, Throwable action) {
                System.out.println(Thread.currentThread().getName()+" 执行完成！");
            }

        });
        future.exceptionally(new Function<Throwable, Void>() {
            @Override
            public Void apply(Throwable t) {
                System.out.println(Thread.currentThread().getName()+" 执行失败！"+t.getMessage());
                return null;
            }
        });
        System.out.println(Thread.currentThread().getName()+" sleep...2" );
        TimeUnit.SECONDS.sleep(2);
    }
    public static void whenCompleteJava8() throws Exception {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            ThreadUtil.sleep(100);
            return 10 / 0;
        }).whenCompleteAsync((v, e) -> {
            System.out.println(Thread.currentThread().getName()+" "+v);
            System.out.println(Thread.currentThread().getName()+" "+e);
        }).exceptionally((e) -> {
            System.out.println(Thread.currentThread().getName()+" "+e.getMessage());
            return 30;
        });
        System.out.println(Thread.currentThread().getName()+" "+future.get());
    }
}
